/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package 解析.node.node;

import 解析.node.others.TreeInfo;
import 解析.Matcher;

/**
 *
 * @author yanxi
 */
public class Loop extends Node {

    private Node body;
    public int countIndex; // local count index in matcher locals
    public int beginIndex; // group beginning index
    public int cmin, cmax;

    public Loop(int countIndex, int beginIndex) {
        this.countIndex = countIndex;
        this.beginIndex = beginIndex;   
    }
    
    public Node getBody() {
        return body;
    }

    public void setBody(Node body) {
        this.body = body; 
        getChildren().add(body);
    }

    @Override
    public boolean match(Matcher matcher, int i, CharSequence seq) {
        // Avoid infinite loop in zero-length case.
        if (i > matcher.locals[beginIndex]) {
            int count = matcher.locals[countIndex];

            // This block is for before we reach the minimum
            // iterations required for the loop to match
            if (count < cmin) {
                matcher.locals[countIndex] = count + 1;
                boolean b = body.match(matcher, i, seq);
                // If match failed we must backtrack, so
                // the loop count should NOT be incremented
                if (!b) {
                    matcher.locals[countIndex] = count;
                }
                // Return success or failure since we are under
                // minimum
                return b;
            }
            // This block is for after we have the minimum
            // iterations required for the loop to match
            if (count < cmax) {
                matcher.locals[countIndex] = count + 1;
                boolean b = body.match(matcher, i, seq);
                // If match failed we must backtrack, so
                // the loop count should NOT be incremented
                if (!b) {
                    matcher.locals[countIndex] = count;
                } else {
                    return true;
                }
            }
        }
        return next.match(matcher, i, seq);
    }

    boolean matchInit(Matcher matcher, int i, CharSequence seq) {
        int save = matcher.locals[countIndex];
        boolean ret = false;
        if (0 < cmin) {
            matcher.locals[countIndex] = 1;
            ret = body.match(matcher, i, seq);
        } else if (0 < cmax) {
            matcher.locals[countIndex] = 1;
            ret = body.match(matcher, i, seq);
            if (ret == false) {
                ret = next.match(matcher, i, seq);
            }
        } else {
            ret = next.match(matcher, i, seq);
        }
        matcher.locals[countIndex] = save;
        return ret;
    }

    @Override
    public boolean study(TreeInfo info) {
        info.maxValid = false;
        info.deterministic = false;
        return false;
    } 
    
    @Override
    public String toString(){
        //return "["+this.getClass().getName()+"]"+"countIndex:"+countIndex+",cmin:"+cmin+",cmax:"+cmax+",beginIndex:"+beginIndex;
        String s=body.toString();
        if(cmin==0&&cmax==1){
            s+="?";
        }
        else if(cmax==2147483647){
            if(cmin==0)s+="*";
            else if(cmin==1)s+="+";
            else s+="{"+cmin+",}";
        } 
        else{
            if(cmin==cmax)s+="{"+cmin+"}";
            else s+="{"+cmin+","+cmax+"}";
        } 
        return s;
    }
}
